package com.mutouren.common.orm;

import java.io.Serializable;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;

@SuppressWarnings(value={"unchecked", "rawtypes"})
public class HibernateHelper {
	
	private static void queryLoadParamer(Query query, List<HibernateParamer> listParam) {
		if(listParam == null) return;
		
		for(HibernateParamer param : listParam) {
			if (param.getParamObject() instanceof List) {
				if(param.getParamType() == null) {
					query.setParameterList(param.getParamName(), (List)param.getParamObject());
				} else {
					query.setParameterList(param.getParamName(), (List)param.getParamObject(), param.getParamType());
				}
				
			} else {			
				if(param.getParamType() == null) {
					query.setParameter(param.getParamName(), param.getParamObject());
				} else {
					query.setParameter(param.getParamName(), param.getParamObject(), param.getParamType());
				}
			}
		}
	}
	
	private static <T> T executeWithNewSession(HibernateCallback<T> action) {
		HibernateTrans trans = new HibernateTrans();
		try{
			trans.begin();
			T result = action.doInHibernate(trans.getSession());
			trans.commit();
			return result;
		} catch(RuntimeException ex) {
			trans.rollback();
			throw ex;
		} finally {
			trans.close();
		}
	}
	
	private static <T> T execute(HibernateCallback<T> action, HibernateTrans trans) {
		if(trans == null) {
			return executeWithNewSession(action);
		} else {			
			return action.doInHibernate(trans.getSession());
		}
	}
	
	public static Object getValue() {
		return null;
	}
	
	public static <T> T get(final Class<T> entityClass, final Serializable id) {
		return get(entityClass, id, null);
	}
	public static <T> T get(final Class<T> entityClass, final Serializable id, HibernateTrans trans) {
		return execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) {
				return (T) session.get(entityClass, id);				
			}
		}, trans);
	}
	
	public static Object selectOnlyOne(String sqlText, List<HibernateParamer> listParam) {
		return selectOnlyOne(sqlText, listParam, null);
	}
	public static Object selectOnlyOne(final String sqlText, final List<HibernateParamer> listParam, 
			HibernateTrans trans) {
		return execute(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) {				
				Query query = session.createQuery(sqlText);
				queryLoadParamer(query, listParam);		
				return query.setMaxResults(1).uniqueResult();				
			}				
		}, trans);						
	}
	
	public static <T> List<T> select(final String sqlText, final List<HibernateParamer> listParam) {
		return select(sqlText, listParam, null);
	}	
	public static <T> List<T> select(final String sqlText, final List<HibernateParamer> listParam, 
			HibernateTrans trans) {
		return execute(new HibernateCallback<List<T>>() {
			@Override
			public List<T> doInHibernate(Session session) {				
				Query query = session.createQuery(sqlText);
				queryLoadParamer(query, listParam);		
				return query.list();				
			}
		}, trans);
	}
	
	public static <T> List<T> selectByNativeSql(Class<T> entityClass, final String sqlText, 
			final List<HibernateParamer> listParam) {
		return selectByNativeSql(entityClass, sqlText, listParam, null);
	}
	public static <T> List<T> selectByNativeSql(final Class<T> entityClass, final String sqlText, 
			final List<HibernateParamer> listParam, HibernateTrans trans) {				
		return execute(new HibernateCallback<List<T>>() {
			
			@Override
			public List<T> doInHibernate(Session session) {				
				SQLQuery query = session.createSQLQuery(sqlText);
				query.addEntity(entityClass);
				queryLoadParamer(query, listParam);		
				return query.list();				
			}
		}, trans);
	}
	
	public static void save(final Object entity) {
		save(entity, null);
	}
	public static void save(final Object entity, HibernateTrans trans) {
		execute(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) {
				session.save(entity);
				return null;				
			}
		}, trans);
	}
	
	public static void update(final Object entity) {
		update(entity, null);
	}
	public static void update(final Object entity, HibernateTrans trans) {
		execute(new HibernateCallback<Object>() {
			@Override
			public Object doInHibernate(Session session) {
				session.update(entity);
				return null;				
			}
		}, trans);
	}
	
	public static <T> void delete(Class<T> entityClass, Serializable id) {
		delete(entityClass, id, null);
	}
	public static <T> void delete(final Class<T> entityClass, final Serializable id, HibernateTrans trans) {
		execute(new HibernateCallback<Object>() {
			
			@Override
			public Object doInHibernate(Session session) {
				Object temp = session.load(entityClass, id);
				session.delete(temp);
				return null;				
			}
		}, trans);
	}
	
	public static <T>  T load(Class<T> entityClass, Serializable id) {
	    return load(entityClass, id, null);
	}
	
	public static <T> T load(final Class<T> entityClass, final Serializable id, HibernateTrans trans) {
		return execute(new HibernateCallback<T>() {
			@Override
			public T doInHibernate(Session session) {
				return (T) session.load(entityClass, id);				
			}
		}, trans);
	}	
	
	public static int bulkUpdate(final String sqlText, final List<HibernateParamer> listParam) {
		return bulkUpdate(sqlText, listParam, null);
	}
	public static int bulkUpdate(final String sqlText, final List<HibernateParamer> listParam, 
			HibernateTrans trans) {
		
		return execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) {				
				Query query = session.createQuery(sqlText);
				queryLoadParamer(query, listParam);		
				return query.executeUpdate();			
			}
		}, trans);
	}
	
	public static int updateByNativeSql(final String sqlText, final List<HibernateParamer> listParam) {
		return updateByNativeSql(sqlText, listParam, null);
	}	
	public static int updateByNativeSql(final String sqlText, final List<HibernateParamer> listParam, 
			HibernateTrans trans) {
		
		return execute(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) {	
				SQLQuery query = session.createSQLQuery(sqlText);
				queryLoadParamer(query, listParam);
				return query.executeUpdate();			
			}
		}, trans);
	}	
}

